package com.fadadianqi.logistics.customer.service;

import com.fadadianqi.logistics.admin.controller.DateTimeHelper;
import com.fadadianqi.logistics.admin.printer.PrintService;
import com.fadadianqi.commons.ConfigHelper;
import com.fadadianqi.commons.VelocityWrapper;
import com.fadadianqi.logistics.customer.dao.AccountDAO;
import com.fadadianqi.logistics.customer.model.Account;
import com.fadadianqi.logistics.customer.model.Customer;
import com.fadadianqi.logistics.sell.model.Bill;
import com.fadadianqi.logistics.sell.model.Goods;
import com.fadadianqi.logistics.sell.service.BillService;
import com.yeqiangwei.commons.util.Pagination;
import com.yeqiangwei.commons.util.ValidatorHelper;
import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.awt.print.Paper;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


@Service
public class AccountService {

    private static final Logger log = Logger.getLogger(AccountService.class);

    /**
     * 对账
     *
     * @param customerId
     * @param begin
     * @param end
     * @throws Exception
     */
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void confirm(String customerId, Date begin, Date end) throws Exception {
        List<Account> accounts = accountDAO.findByCustomerIdBetween(customerId, begin, end, null);
        if (ValidatorHelper.isEmpty(accounts)) {
            return;
        }
        List<Item> items = new ArrayList<AccountService.Item>();
        for (Account account : accounts) {
            Customer customer = customerService.getById(customerId);
            String billId = account.getBillId();
            Bill bill = billService.getById(billId);
            List<Goods> goods = billService.findGoodsByBillId(billId);
            Item item = new Item();
            item.setAccount(account);
            item.setBill(bill);
            item.setCustomer(customer);
            item.setGoods(goods);
            items.add(item);
        }
        String content = getContent(items);
        doPrint(content);
    }

    private void doPrint(String content) throws Exception {
        int offsetX = ConfigHelper.getInt("vm.printer.offsetX", 10);
        int offsetY = ConfigHelper.getInt("vm.printer.offsetY", 10);
        int width = ConfigHelper.getInt("vm.printer.width", 585);
        int height = ConfigHelper.getInt("vm.printer.height", 800);
        Paper p = new Paper();
        p.setSize(width, height); // 纸张大小
        p.setImageableArea(offsetX, offsetY, width, height);
        PrintService printService = new PrintService(content, p);
        printService.doPrint();
    }

    private String getContent(List<Item> items) {
        String baseDir = System.getProperty("base.dir", "..");
        String path = baseDir + "printer" + File.separator;
        VelocityEngine ve = VelocityWrapper.getVelocityInstance();
        ve.setProperty("file.resource.loader.path", ConfigHelper.getString("vm.printer.template.path", path));
        Template t = VelocityWrapper.getTemplate(ve, "accountConfirm.vm");
        VelocityContext context = new VelocityContext();
        context.put("items", items);
        StringWriter writer = new StringWriter();
        try {
            t.merge(context, writer);
        } catch (ResourceNotFoundException e) {
            log.error(e.toString());
        } catch (ParseErrorException e) {
            log.error(e.toString());
        } catch (MethodInvocationException e) {
            log.error(e.toString());
        } catch (IOException e) {
            log.error(e.toString());
        }
        return writer.toString();
    }

    public List<Account> findByCustomerId(String customerId, Pagination pagination) {
        if (ValidatorHelper.isEmpty(customerId)) {
            return null;
        }
        pagination.setOrderList(new Pagination.Order[]{
                Pagination.getNewOrder("id", Pagination.Order.DESCENDING)
        });
        return accountDAO.findByCustomerId(customerId, pagination);
    }

    public List<Account> findByBillId(Bill bill) {
        if (bill == null) {
            return null;
        }
        return accountDAO.findByBillId(bill.getId());
    }

    public int countByCustomerId(String customerId) {
        if (ValidatorHelper.isEmpty(customerId)) {
            return 0;
        }
        return accountDAO.countByCustomerId(customerId);
    }


    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Throwable.class)
    public void create(Account account) {
        Customer customer = customerService.getById(account.getCustomerId());
        if (customer == null) {
            return;
        }
        double balance = getBalance(customer);
        double d = balance + account.getMoney();
        account.setBalance(d); // 本次入帐后的余额
        accountDAO.create(account);

        // 冗余记录客户的余额
        customer.setBalance(d);
        customerService.saveCustomer(customer);
    }

    public void remove(Account a) {
        accountDAO.remove(a);
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = true, rollbackFor = Throwable.class)
    public double getBalance(Customer customer) {
        if (customer == null) {
            return 0D;
        }
        Pagination pagination = new Pagination(1, 1);
        pagination.setOrderList(new Pagination.Order[]{
                Pagination.getNewOrder("id", Pagination.Order.DESCENDING)
        });
        List<Account> list = accountDAO.findByCustomerId(customer.getId(), pagination);
        if (list != null && list.size() > 0) {
            return list.get(0).getBalance();
        }
        return 0;
    }

    /**
     * 起初余额
     *
     * @param customer
     * @param time
     * @return
     */
    public double getBalanceBegin(Customer customer, Date time) {
        if (customer == null) {
            return 0D;
        }
        Pagination pagination = new Pagination(1, 1);
        pagination.setOrderList(new Pagination.Order[]{
                Pagination.getNewOrder("id", Pagination.Order.ASCENDING)
        });
        Date b = DateTimeHelper.getOfDayStart(time);
        Date e = DateTimeHelper.getOfDayEnd(time);
        List<Account> list = accountDAO.findByCustomerIdBetween(customer.getId(), b, e, pagination);
        if (list != null && list.size() > 0) {
            return list.get(0).getBalance();
        }
        return 0;
    }

    /**
     * 期末余额
     *
     * @param customer
     * @param time
     * @return
     */
    public double getBalanceEnd(Customer customer, Date time) {
        if (customer == null) {
            return 0D;
        }
        Date e = DateTimeHelper.getOfDayEnd(time);
        List<Account> list = accountDAO.getBalanceEnd(customer.getId(), e);
        if (list != null && list.size() > 0) {
            return list.get(0).getBalance();
        }
        return 0;
    }

    @Autowired
    private AccountDAO accountDAO;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private BillService billService;

    public static class Item implements java.io.Serializable {

        /**
         *
         */
        private static final long serialVersionUID = 5656576205832627967L;

        private Bill bill;
        private List<Goods> goods;
        private Account account;
        private Customer customer;

        public Bill getBill() {
            return bill;
        }

        public void setBill(Bill bill) {
            this.bill = bill;
        }

        public List<Goods> getGoods() {
            return goods;
        }

        public void setGoods(List<Goods> goods) {
            this.goods = goods;
        }

        public Account getAccount() {
            return account;
        }

        public void setAccount(Account account) {
            this.account = account;
        }

        public Customer getCustomer() {
            return customer;
        }

        public void setCustomer(Customer customer) {
            this.customer = customer;
        }
    }

}

